StateX class topic

The State Class Extended

Extend the capabilities of Flutter’s own State class. This class allows you to use a State Object Controller (SOC) to reliably call the State object's setState() function from outside its class — a very powerful capability!

This class provides the initAsync() function to perform any asynchronous operations before displaying its contents. It also provides the dependOnInheritedWidget() function to assign a widget as a 'dependency' to the StateX's built-in InheritedWidget. It then uses its notifyClients() function to spontaneously rebuilt only those widgets. Very powerful!

Contents
Code State Pattern Sync Sync Interface? Inherit
The StateX class gives you five new functions and features:

Control Your Code

All your ‘mutable’ code should go into your State Object Controller. It would contain the ‘business logic’ involved in a given app as well as address any event handling. Controllers are not new to Flutter. Two popular widgets that use a controller, for example, is the TextField widget and the SingleChildScrollView widget.

However, unlike those two widgets, a StateX object can have any number of controllers. This promotes more modular development where each controller is dedicated to a particular responsibility independent of other controllers. This further relieves any 'controller bloat' common when involving a controller ( see State Object Controller).

State Pattern

A common pattern seen when implementing a controller for use by a StateX object will have the controller object instantiated right in the State object and then referenced here and there in the State object’s build() function. Thus providing the data and the event handling. For example, the first screenshot below is of the ' counter example app' that uses this package. The second screenshot shows how a number of controllers can be added.
(A controller and its use are highlighted by red arrows.)
_MyHomePageState Page1State

Sync The State

There's now a means to deal with asynchronous operations in the State object before rendering its interface. A common approach has been to execute such operations even before the app begins---a disjointed approach. The operation is not done by the actual State object (the actual screen) where it's relevant or required. However, Flutter has always had the FutureBuilder widget to make this possible. A FutureBuilder widget is built into the StateX class, and has its initAsync() function to then perform such asynchronous operations. As a result, when such a State object is called, it can wait for its asynchronous operations to complete before proceeding. As easy as that.

Below are three gif files. The first one depicts what a user will see more often than not when starting up an app written with this package. There's always a remote database to open or web services to connect to and this takes a little time. You don't want your user staring at a blank screen. They'll think the app is frozen! A spinner is displayed indicating the app is indeed running. The second gif file depicts twelve separate StateX objects waiting to continue. Each has its own individual asynchronous operation loading a animal graphic from some REST api somewhere. The last gif file shows the whole startup process for this particular app. It carry's on and shows you they are indeed individual operations ending with a different picture.

In this case, since they're running on an Android emulator, those spinners are from the CircularProgressIndicator widget. If they were running on an iOS phone, the CupertinoActivityIndicator widget would produce the iOS-style activity indicators instead. Flutter is a cross-platform SDK after all.
image_api_controller.dart working_memory_app.dart

Control The Sync

Those three screens above are from the example app supplied with this package. Yes, there are twelve separate StateX objects on that one screen each loading an animal image. Actually its their own individual State Object Controller that's performing the asynchronous download. Above, is a screenshot of that controller's own initAsync() function. While each controller is calling its _loadImage() function, its associated StateX object will quietly wait with its indicator spinning away on the screen. Very nice.

The screenshot on the right is another initAsync() function from another app altogether. It demonstrates there can be a number of asynchronous operations performed before an app can continue. This particular app involves the authentication of the user for example. If not already logged in a login screen will appear. This function is in another controller and that controller calls yet another controller to run its own initAsync(). See how you're able to separate distinct asynchronous operations each prefixed with an await operator and returning a boolean value to the variable, init. It's all easy to read and all in the right location to be implemented.

It's suggested you implement such operations in a Controller, and not directly in a StateX object. Besides, the StateX object's own initAsync() function is already implemented: It's calling all the initAsync() functions from its associated State Object Controllers. When they're all complete, only then does the StateX object call its build() function. Since most asynchronous operations have no direct relation to an app’s interface, you’ll likely have your asynchronous stuff running in a State Object Controller anyway with the rest of the app’s business logic. See how that works?

There can be individual controllers running their own initAsync() function. Very clean. Very modular.

Inherit The State

You've may have been introduced to the InheritedWidget, and how it allows you to repel down the widget tree any piece of data you've designated. However, a more intriguing feature is whenever you call an already instantiated InheritedWidget, any widgets assigned as its dependents are rebuilt (their build() functions run again)---as if their setState() functions were explicitly called.Now that allows for improved performance with the refresh of only specific areas of the interface.

Even the efficiency of the humble 'counter app' is greatly improved. Instead of refreshing the whole screen (including the StatelessWidget with its 'You have pushed the button this many times') , when the 'Use the built-in InheritedWidget' switch is on, only the lone widget displaying the current count is then ever rebuilt. The rest of the screen would now be left alone with every press of that button. Granted this is a very simple interface and possibly a bad example, but look how easy this is implemented in the screenshot below.
counter_app.dart

The setBuilder() function found will allow for this immediate improvement in efficiency. When it comes to interfaces, the less that's rebuilt, the better.

Back to the app with its grid of animal pictures, you can see above when the 'new dogs' text button is pressed, only the three 'dog pictures' are downloaded again. What your seeing are only three portions of the screen being updated---only three widgets being rebuilt. If the whole screen was rebuilt, all the pictures would change. Not very effective.

counter_app.dart

The screenshot above depicts one of the three widgets being assigned as a dependent to a State object's InheritedWidget using the dependOnInheritedWidget() function. In fact, the State object's controller with its own dependOnInheritedWidget() function is actually used.

Classes

AppStateMixin StateX class State Object Controller
Supply access to the 'App' State object.
AppStateX<T extends StatefulWidget> Get started StateX class AppStateX class
The StateX object at the 'app level.' Used to effect the whole app by being the first State object instantiated.
ImplNotifyListenersChangeNotifier StateX class State Object Controller
Implements the ChangeNotifier for both StateX ans StateXController
RouteObserverStates StateX class State Object Controller
Makes every StateX and StateXController a RouteAware object calling didPop, didPush, didPopNext and didPushNext Implemented by default.
StateDependentWidget StateX class AppStateX class
Used by the setBuilder function in both AppStateX and StateX Supply a widget to depend the built-in InheritedWidget
StateX<T extends StatefulWidget> Get started StateX class Using FutureBuilder Using InheritedWidget Error handling Testing Event handling
An extension of Flutter's State class.
StateXInheritedWidget StateX class
The built-in InheritedWidget used by StateX
StateXonErrorMixin StateX class Error handling
Supply an 'error handler' routine if something goes wrong. It need not be implemented, but it's their for your consideration.
Uuid StateX class State Object Controller
Shamelessly extracted from the author of Scoped Model plugin, Who maybe took from the Flutter source code. I'm not telling!
WidgetsBindingInstanceMixin StateX class State Object Controller
Implements inWidgetsFlutterBinding and inFlutterTest for both StateX and StateXController

Mixins

AsyncOps StateX class State Object Controller
Supply the Async API to StateX and StateXController initAsync, initAsyncState and onAsyncError
ErrorInErrorHandlerMixin StateX class Error handling
Record errors in the Error Handler itself The developer has introduces an error in the handling itself. They must be notified. recordErrorInHandler, recErrorMsg, recErrorException, recStackTrace
FutureBuilderStateMixin StateX class Using FutureBuilder
Supply the built-in FutureBuilder to the StateX object. build is overwritten. See Implementation See: initAsync, onAsyncError and buildF
InheritedWidgetStateMixin StateX class Using InheritedWidget
Supplies the built-in InheritedWidget to a StateX class
MapOfStateXsMixin StateX class
Works with the collection of State objects in the App.
RootStateMixin StateX class State Object Controller
Deprecated, Use AppStateMixin mixin instead.
StateXControllersByTypeMixin StateX class
Collects Controllers of various types. A State object, by definition, then can't have multiple instances of the same type.
StateXEventHandlers StateX class State Object Controller Event handling
Supplies the event handling in all the StateXController and StateX objects.